package com.example.teesystem.service.impl;

import cn.hutool.core.lang.hash.Hash;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.teesystem.common.cache.KnowledgeCache;
import com.example.teesystem.common.cache.UserCache;
import com.example.teesystem.common.utils.DocUtil;
import com.example.teesystem.common.utils.IssueUtil;
import com.example.teesystem.common.utils.Response;
import com.example.teesystem.common.utils.ResultCode;
import com.example.teesystem.entity.Class;
import com.example.teesystem.entity.*;
import com.example.teesystem.entity.vo.PageRequestVo;
import com.example.teesystem.entity.vo.PageResponseVo;
import com.example.teesystem.entity.vo.examEvaluation.WordVo;
import com.example.teesystem.entity.vo.examPaper.ExamPaperSelectVo1;
import com.example.teesystem.entityDto.*;
import com.example.teesystem.filter.MyHandlerInterceptor;
import com.example.teesystem.mapper.*;
import com.example.teesystem.service.ExamEvaluationService;
import com.example.teesystem.service.ExamIssueService;
import lombok.RequiredArgsConstructor;
import org.apache.tomcat.util.buf.StringUtils;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author NieYaShi
 * @description 针对表【t_exam_evaluation】的数据库操作Service实现
 * @createDate 2022-04-19 14:44:43
 */
@Service
@RequiredArgsConstructor
public class ExamEvaluationServiceImpl extends ServiceImpl<ExamEvaluationMapper, ExamEvaluation>
        implements ExamEvaluationService {

    private final IssueRecordMapper issueRecordMapper;
    private final IssueMapper issueMapper;
    private final ExamPaperMapper examPaperMapper;
    private final ExamIssueMapper examIssueMapper;
    private final ExamEvaluationMapper examEvaluationMapper;
    private final ChapterMapper chapterMapper;
    private final ClassStudentMapper classStudentMapper;
    private final CourseMapper courseMapper;
    private final ClassMapper classMapper;
    private final PaperFeedbackMapper paperFeedbackMapper;
    private final ExamIssueService examIssueService;

    @Override
    public Response getStudentIssueCorrect() {
        Map<String, Float> result = new HashMap<>();

        QueryWrapper<IssueRecord> issueRecordQueryWrapper = new QueryWrapper<>();
        issueRecordQueryWrapper
                .eq("student_id", MyHandlerInterceptor.getUid())
                .orderByAsc("issue_id");
        List<IssueRecord> issueRecordList = issueRecordMapper.selectList(issueRecordQueryWrapper);
        if (issueRecordList.size() == 0){
            return Response.ok(result);
        }

        List<Integer> issueIds = new ArrayList<>();
        for (IssueRecord issueRecord : issueRecordList) {
            issueIds.add(issueRecord.getIssueId());
        }
        QueryWrapper<Issue> issueQueryWrapper = new QueryWrapper<>();
        issueQueryWrapper
                .in("id", issueIds)
                .orderByAsc("id");
        List<Issue> issueList = issueMapper.selectList(issueQueryWrapper);

        Map<Integer, List<IssueRecord>> recodeMap = getRecordeMap(issueRecordList, issueList);

        for (Integer key : recodeMap.keySet()) {
            float rightNum = 0;
            float wrongNum = 0;
            for (IssueRecord issueRecord : recodeMap.get(key)) {
                rightNum += issueRecord.getRightNum();
                wrongNum += issueRecord.getWrongNum();
            }
            float correct = rightNum / (rightNum + wrongNum);
            result.put(IssueUtil.getIssueTypeName(key), correct);
        }

        return Response.ok(result);
    }

    @Override
    public Response getStudentIssueAvgDifficulty() {
        Map<String, Float> result = new HashMap<>();

        QueryWrapper<IssueRecord> issueRecordQueryWrapper = new QueryWrapper<>();
        issueRecordQueryWrapper
                .eq("student_id", MyHandlerInterceptor.getUid())
                .orderByAsc("issue_id");
        List<IssueRecord> issueRecordList = issueRecordMapper.selectList(issueRecordQueryWrapper);
        if (issueRecordList.size() == 0){
            return Response.ok(result);
        }

        List<Integer> issueIds = new ArrayList<>();
        for (IssueRecord issueRecord : issueRecordList) {
            issueIds.add(issueRecord.getIssueId());
        }
        QueryWrapper<Issue> issueQueryWrapper = new QueryWrapper<>();
        issueQueryWrapper
                .in("id", issueIds)
                .orderByAsc("id");
        List<Issue> issueList = issueMapper.selectList(issueQueryWrapper);

        Map<Integer, List<Issue>> issueMap = issueList.stream().collect(Collectors.groupingBy(
                Issue::getType));

        for (Integer key : issueMap.keySet()) {
            float difficulty = 0;
            for (Issue issue : issueMap.get(key)) {
                difficulty += issue.getDifficulty();
            }
            result.put(IssueUtil.getIssueTypeName(key), difficulty / issueMap.get(key).size());
        }

        return Response.ok(result);
    }

    private Map<Integer, List<IssueRecord>> getRecordeMap(List<IssueRecord> issueRecordList, List<Issue> issueList) {
        Map<Integer, List<IssueRecord>> recordeMap = new HashMap<>();
        for (int i = 0; i < issueRecordList.size(); i++) {
            if (issueList.get(i).getType().equals(IssueUtil.JUDGE)) {
                if (recordeMap.get(IssueUtil.JUDGE) == null) {
                    List<IssueRecord> issueRecords = new ArrayList<>();
                    issueRecords.add(issueRecordList.get(i));
                    recordeMap.put(IssueUtil.JUDGE, issueRecords);
                } else {
                    List<IssueRecord> issueRecords = recordeMap.get(IssueUtil.JUDGE);
                    issueRecords.add(issueRecordList.get(i));
                    recordeMap.put(IssueUtil.JUDGE, issueRecords);
                }
            } else if (issueList.get(i).getType().equals(IssueUtil.FILL_IN_THE_BLANKS)) {
                if (recordeMap.get(IssueUtil.FILL_IN_THE_BLANKS) == null) {
                    List<IssueRecord> issueRecords = new ArrayList<>();
                    issueRecords.add(issueRecordList.get(i));
                    recordeMap.put(IssueUtil.FILL_IN_THE_BLANKS, issueRecords);
                } else {
                    List<IssueRecord> issueRecords = recordeMap.get(IssueUtil.FILL_IN_THE_BLANKS);
                    issueRecords.add(issueRecordList.get(i));
                    recordeMap.put(IssueUtil.FILL_IN_THE_BLANKS, issueRecords);
                }
            } else if (issueList.get(i).getType().equals(IssueUtil.SINGLE_CHOICE)) {
                if (recordeMap.get(IssueUtil.SINGLE_CHOICE) == null) {
                    List<IssueRecord> issueRecords = new ArrayList<>();
                    issueRecords.add(issueRecordList.get(i));
                    recordeMap.put(IssueUtil.SINGLE_CHOICE, issueRecords);
                } else {
                    List<IssueRecord> issueRecords = recordeMap.get(IssueUtil.SINGLE_CHOICE);
                    issueRecords.add(issueRecordList.get(i));
                    recordeMap.put(IssueUtil.SINGLE_CHOICE, issueRecords);
                }
            } else if (issueList.get(i).getType().equals(IssueUtil.MULTIPLE_CHOICE)) {
                if (recordeMap.get(IssueUtil.MULTIPLE_CHOICE) == null) {
                    List<IssueRecord> issueRecords = new ArrayList<>();
                    issueRecords.add(issueRecordList.get(i));
                    recordeMap.put(IssueUtil.MULTIPLE_CHOICE, issueRecords);
                } else {
                    List<IssueRecord> issueRecords = recordeMap.get(IssueUtil.MULTIPLE_CHOICE);
                    issueRecords.add(issueRecordList.get(i));
                    recordeMap.put(IssueUtil.MULTIPLE_CHOICE, issueRecords);
                }
            } else {
                if (recordeMap.get(IssueUtil.BRIEF_ANSWER) == null) {
                    List<IssueRecord> issueRecords = new ArrayList<>();
                    issueRecords.add(issueRecordList.get(i));
                    recordeMap.put(IssueUtil.BRIEF_ANSWER, issueRecords);
                } else {
                    List<IssueRecord> issueRecords = recordeMap.get(IssueUtil.BRIEF_ANSWER);
                    issueRecords.add(issueRecordList.get(i));
                    recordeMap.put(IssueUtil.BRIEF_ANSWER, issueRecords);
                }
            }
        }
        return recordeMap;
    }

    @Override
    public Response getNotMarkExamPaper(ExamPaperSelectVo1 examPaperSelectVo1) {
        List<NotMarkPaperList> notMarkPaperLists = new ArrayList<>();
        PageResponseVo<NotMarkPaperList> pageNotMarkPaperList;

        List<Integer> studentIds = classStudentMapper.getStudentIdByClassId(examPaperSelectVo1.getClassId());
        if (studentIds.size() == 0) {
            pageNotMarkPaperList = new PageResponseVo<>(notMarkPaperLists, examPaperSelectVo1.getCur(), examPaperSelectVo1.getSize(), 1);
            return Response.ok(pageNotMarkPaperList);
        }

        String classIdRegex = getClassRegex(examPaperSelectVo1.getClassId());
        List<ExamPaper> examPaperList = examPaperMapper.getNoMarkedPaperByCourseAndClassId(examPaperSelectVo1.getCourseId(), classIdRegex);
        if (examPaperList.size() == 0) {
            pageNotMarkPaperList = new PageResponseVo<>(notMarkPaperLists, examPaperSelectVo1.getCur(), examPaperSelectVo1.getSize(), 1);
            return Response.ok(pageNotMarkPaperList);
        }
        List<Integer> examPaperIds = new ArrayList<>();
        for (ExamPaper examPaper : examPaperList){
            examPaperIds.add(examPaper.getId());
        }

        for(ExamPaper examPaper : examPaperList){
            for(int i : studentIds){
                examIssueService.getNotMarkIssue(examPaper.getId(),i);
            }
        }

        Page<ExamEvaluation> page = new Page<>(examPaperSelectVo1.getCur(), examPaperSelectVo1.getSize());
        QueryWrapper<ExamEvaluation> examEvaluationQueryWrapper = new QueryWrapper<>();
//        examEvaluationQueryWrapper.in( "paper_id", examPaperIds)
//                .in("student_id",  studentIds)
//                .eq("is_mark", 0)
//                .orderByDesc("paper_id");
        examEvaluationQueryWrapper.eq( "paper_id", examPaperSelectVo1.getPaperId())
                .in("student_id",  studentIds)
                .eq("is_mark", 0)
                .orderByDesc("paper_id");
        Page<ExamEvaluation> myPage = this.page(page, examEvaluationQueryWrapper);
        List<ExamEvaluation> examEvaluationList = myPage.getRecords();

        for (ExamEvaluation examEvaluation : examEvaluationList) {
            for (ExamPaper examPaper : examPaperList){
                if (examPaper.getId().equals(examEvaluation.getPaperId())){
                    notMarkPaperLists.add(new NotMarkPaperList(examEvaluation.getStudentId(), examPaper));
                }
            }
        }

        pageNotMarkPaperList = new PageResponseVo<>(notMarkPaperLists, myPage.getCurrent(), myPage.getSize(), myPage.getPages());

        return Response.ok(pageNotMarkPaperList);
    }

    @Override
    public Response getNotMarkPaperByClassId(ExamPaperSelectVo1 examPaperSelectVo1) {
        List<SimplePaperInfo> SimplePaperInfos = new ArrayList<>();
        PageResponseVo<SimplePaperInfo> pageNotMarkSimplePaperInfoList;

        List<Integer> studentIds = classStudentMapper.getStudentIdByClassId(examPaperSelectVo1.getClassId());
        if (studentIds.size() == 0) {
            pageNotMarkSimplePaperInfoList = new PageResponseVo<>(SimplePaperInfos, examPaperSelectVo1.getCur(), examPaperSelectVo1.getSize(), 1);
            return Response.ok(pageNotMarkSimplePaperInfoList);
        }

        String classIdRegex = getClassRegex(examPaperSelectVo1.getClassId());
        List<ExamPaper> examPaperList = examPaperMapper.getNoMarkedPaperByCourseAndClassId(examPaperSelectVo1.getCourseId(), classIdRegex);
        if (examPaperList.size() == 0) {
            pageNotMarkSimplePaperInfoList = new PageResponseVo<>(SimplePaperInfos, examPaperSelectVo1.getCur(), examPaperSelectVo1.getSize(), 1);
            return Response.ok(pageNotMarkSimplePaperInfoList);
        }
        List<Integer> examPaperIds = new ArrayList<>();
        for (ExamPaper examPaper : examPaperList){
            examPaperIds.add(examPaper.getId());
        }

        for(ExamPaper examPaper : examPaperList){
            for(int i : studentIds){
                examIssueService.getNotMarkIssue(examPaper.getId(),i);
            }
        }

        Page<ExamEvaluation> page = new Page<>(examPaperSelectVo1.getCur(), examPaperSelectVo1.getSize());
        QueryWrapper<ExamEvaluation> examEvaluationQueryWrapper = new QueryWrapper<>();
        examEvaluationQueryWrapper.in( "paper_id", examPaperIds)
                .in("student_id",  studentIds)
                .eq("is_mark", 0)
                .orderByDesc("paper_id");
        Page<ExamEvaluation> myPage = this.page(page, examEvaluationQueryWrapper);
        List<ExamEvaluation> examEvaluationList = myPage.getRecords();

        HashSet<Integer> set = new HashSet<>();
        for (ExamEvaluation examEvaluation : examEvaluationList) {
            for (ExamPaper examPaper : examPaperList){
                if (examPaper.getId().equals(examEvaluation.getPaperId()) && !set.contains(examPaper.getId())){
                    SimplePaperInfos.add(new SimplePaperInfo(examEvaluation.getStudentId(), examPaper));
                    set.add(examPaper.getId());
                }
            }
        }

        pageNotMarkSimplePaperInfoList = new PageResponseVo<>(SimplePaperInfos, myPage.getCurrent(), myPage.getSize(), myPage.getPages());

        return Response.ok(pageNotMarkSimplePaperInfoList);
    }

    @Override
    public Response getMarkExamPaper(ExamPaperSelectVo1 examPaperSelectVo1) {
        List<MarkedPaperList> markedPaperLists = new ArrayList<>();
        PageResponseVo<MarkedPaperList> pageMarkPaperList;

        List<Integer> studentIds = classStudentMapper.getStudentIdByClassId(examPaperSelectVo1.getClassId());
        if (studentIds.size() == 0) {
            return Response.error(ResultCode.CLASS_STUDENT_NULL_ERROR);
        }

        String classIdRegex = getClassRegex(examPaperSelectVo1.getClassId());
        List<ExamPaper> examPaperList = examPaperMapper.getMarkedPaperByCourseAndClassId(examPaperSelectVo1.getCourseId(), classIdRegex);
        if (examPaperList.size() == 0) {
            pageMarkPaperList = new PageResponseVo<>(markedPaperLists, examPaperSelectVo1.getCur(), examPaperSelectVo1.getSize(), 1);
            return Response.ok(pageMarkPaperList);
        }
        List<Integer> examPaperIds = new ArrayList<>();
        for (ExamPaper examPaper : examPaperList){
            examPaperIds.add(examPaper.getId());
        }

        Page<ExamEvaluation> page = new Page<>(examPaperSelectVo1.getCur(), examPaperSelectVo1.getSize());
        QueryWrapper<ExamEvaluation> examEvaluationQueryWrapper = new QueryWrapper<>();
        examEvaluationQueryWrapper.in( "paper_id", examPaperIds)
                .in("student_id",  studentIds)
                .eq("is_mark", 1)
                .orderByDesc("paper_id");

        Page<ExamEvaluation> myPage = this.page(page, examEvaluationQueryWrapper);
        List<ExamEvaluation> examEvaluationList = myPage.getRecords();

        for (ExamEvaluation examEvaluation : examEvaluationList) {
            for (ExamPaper examPaper : examPaperList){
                if (examPaper.getId().equals(examEvaluation.getPaperId())){
                    markedPaperLists.add(new MarkedPaperList(examEvaluation.getStudentId(), examPaper, examEvaluation));
                }
            }
        }

        pageMarkPaperList = new PageResponseVo<>(markedPaperLists, myPage.getCurrent(), myPage.getSize(), myPage.getPages());

        return Response.ok(pageMarkPaperList);
    }

    @Override
    public Response getMarkPaperSimpleList(ExamPaperSelectVo1 examPaperSelectVo1) {
        List<SimplePaperInfo> SimplePaperInfos = new ArrayList<>();
        PageResponseVo<SimplePaperInfo> pageMarkPaperList;

        List<Integer> studentIds = classStudentMapper.getStudentIdByClassId(examPaperSelectVo1.getClassId());
        if (studentIds.size() == 0) {
            return Response.error(ResultCode.CLASS_STUDENT_NULL_ERROR);
        }

        String classIdRegex = getClassRegex(examPaperSelectVo1.getClassId());
        List<ExamPaper> examPaperList = examPaperMapper.getMarkedPaperByCourseAndClassId(examPaperSelectVo1.getCourseId(), classIdRegex);
        if (examPaperList.size() == 0) {
            pageMarkPaperList = new PageResponseVo<>(SimplePaperInfos, examPaperSelectVo1.getCur(), examPaperSelectVo1.getSize(), 1);
            return Response.ok(pageMarkPaperList);
        }
        List<Integer> examPaperIds = new ArrayList<>();
        for (ExamPaper examPaper : examPaperList){
            examPaperIds.add(examPaper.getId());
        }

        Page<ExamEvaluation> page = new Page<>(examPaperSelectVo1.getCur(), examPaperSelectVo1.getSize());
        QueryWrapper<ExamEvaluation> examEvaluationQueryWrapper = new QueryWrapper<>();
        examEvaluationQueryWrapper.in( "paper_id", examPaperIds)
                .in("student_id",  studentIds)
                .eq("is_mark", 1)
                .orderByDesc("paper_id");

        Page<ExamEvaluation> myPage = this.page(page, examEvaluationQueryWrapper);
        List<ExamEvaluation> examEvaluationList = myPage.getRecords();

        HashSet<Integer> set = new HashSet<>();
        for (ExamEvaluation examEvaluation : examEvaluationList) {
            for (ExamPaper examPaper : examPaperList){
                if (examPaper.getId().equals(examEvaluation.getPaperId()) && !set.contains(examPaper.getId())){
                    SimplePaperInfos.add(new SimplePaperInfo(examEvaluation.getStudentId(), examPaper));
                    set.add(examPaper.getId());
                }
            }
        }

        pageMarkPaperList = new PageResponseVo<>(SimplePaperInfos, myPage.getCurrent(), myPage.getSize(), myPage.getPages());

        return Response.ok(pageMarkPaperList);
    }

    @Override
    public Response studentGetMarkedPaperList(PageRequestVo pageRequestVo) {
        List<StudentMarkedPaperList> studentMarkedPaperLists = new ArrayList<>();
        PageResponseVo<StudentMarkedPaperList> pageResponseVo;

        Page<ExamEvaluation> page = new Page<>(pageRequestVo.getCur(), pageRequestVo.getSize());
        QueryWrapper<ExamEvaluation> examEvaluationQueryWrapper = new QueryWrapper<>();
        examEvaluationQueryWrapper
                .eq("student_id", MyHandlerInterceptor.getUid())
                .eq("is_mark", 1)
                .eq("is_publish", 1)
                .orderByDesc("paper_id");
        Page<ExamEvaluation> myPage = this.page(page, examEvaluationQueryWrapper);
        List<ExamEvaluation> examEvaluationList = myPage.getRecords();
        if (examEvaluationList.size() == 0){
            return Response.ok(new PageResponseVo<>(studentMarkedPaperLists, pageRequestVo.getCur(), pageRequestVo.getSize(), 1));
        }

        List<Integer> paperIds = new ArrayList<>();
        for (ExamEvaluation examEvaluation : examEvaluationList) {
            paperIds.add(examEvaluation.getPaperId());
        }

        QueryWrapper<ExamPaper> wrapper = new QueryWrapper<>();
        wrapper.in("id", paperIds)
                .eq("is_publish", 1)
                .eq("is_finish", 1)
                .orderByDesc("id");
        List<ExamPaper> examPaperList = examPaperMapper.selectList(wrapper);
        if (examPaperList.size() == 0) {
            return Response.ok(new PageResponseVo<>(studentMarkedPaperLists, pageRequestVo.getCur(), pageRequestVo.getSize(), 1));
        }

        for (int i = 0; i < examEvaluationList.size(); i++) {
            studentMarkedPaperLists.add(new StudentMarkedPaperList(examPaperList.get(i), examEvaluationList.get(i)));
        }

        pageResponseVo = new PageResponseVo<>(studentMarkedPaperLists, myPage.getCurrent(), myPage.getSize(), myPage.getPages());

        return Response.ok(pageResponseVo);
    }

    private String getClassRegex(int classId){
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("^");
        stringBuilder.append(classId);
        stringBuilder.append("$|^");
        stringBuilder.append(classId);
        stringBuilder.append("\\$|\\$");
        stringBuilder.append(classId);
        stringBuilder.append("\\$|\\$");
        stringBuilder.append(classId);
        stringBuilder.append("$");
        return stringBuilder.toString();
    }

    @Override
    public Response getExamIssueTypeDistribution(Integer courseId, Integer paperId) {
        Map<String, Integer> result = new HashMap<>();

        ExamPaper check = examPaperMapper.getPaperByCourseIdAndId(courseId, paperId);
        if (check == null) {
            return Response.ok(result);
        }

        QueryWrapper<ExamIssue> examIssueQueryWrapper = new QueryWrapper<>();
        examIssueQueryWrapper
                .eq("paper_id", paperId)
                .orderByAsc("issue_id");
        List<ExamIssue> examIssueList = examIssueMapper.selectList(examIssueQueryWrapper);
        if (examIssueList.size() == 0){
            return Response.ok(result);
        }

        List<Integer> issueIds = new ArrayList<>();
        for (ExamIssue examIssue : examIssueList) {
            issueIds.add(examIssue.getIssueId());
        }
        List<Issue> issueList = issueMapper.getIssuesByIds(issueIds);

        Map<Integer, List<ExamIssue>> examIssueMap = getExamIssueMap(examIssueList, issueList);

        for (Integer key : examIssueMap.keySet()) {
            result.put(IssueUtil.getIssueTypeName(key), examIssueMap.get(key).size());
        }

        return Response.ok(result);
    }

    @Override
    public Response getExamIssueTypeAvgDifficulty(Integer courseId, Integer paperId) {
        Map<String, Float> result = new HashMap<>();

        ExamPaper check = examPaperMapper.getPaperByCourseIdAndId(courseId, paperId);
        if (check == null) {
            return Response.ok(result);
        }
        List<ExamIssue> examIssueList = examIssueMapper.getExamIssueByPaperId(paperId);
        if (examIssueList.size() == 0){
            return Response.ok(result);
        }

        List<Integer> issueIds = new ArrayList<>();
        for (ExamIssue examIssue : examIssueList) {
            issueIds.add(examIssue.getIssueId());
        }
        List<Issue> issueList = issueMapper.getIssuesByIds(issueIds);

        Map<Integer, List<Issue>> issueMap = issueList.stream().collect(Collectors.groupingBy(
                Issue::getType));

        for (Integer key : issueMap.keySet()) {
            float difficulty = 0;
            for (Issue issue : issueMap.get(key)) {
                difficulty += issue.getDifficulty();
            }

            float avgDiff = difficulty / issueMap.get(key).size();
            result.put(IssueUtil.getIssueTypeName(key),  (float)Math.round(avgDiff * 100) / 100);
        }
        return Response.ok(result);
    }

    @Override
    public Response getExamIssueScoreDistribution(Integer courseId, Integer paperId) {
        Map<String, Integer> result = new HashMap<>();

        ExamPaper check = examPaperMapper.getPaperByCourseIdAndId(courseId, paperId);
        if (check == null) {
            return Response.ok(result);
        }

        QueryWrapper<ExamIssue> examIssueQueryWrapper = new QueryWrapper<>();
        examIssueQueryWrapper
                .eq("paper_id", paperId)
                .orderByAsc("issue_id");
        List<ExamIssue> examIssueList = examIssueMapper.selectList(examIssueQueryWrapper);
        if (examIssueList.size() == 0){
            return Response.ok(result);
        }

        List<Integer> issueIds = new ArrayList<>();
        for (ExamIssue examIssue : examIssueList) {
            issueIds.add(examIssue.getIssueId());
        }
        List<Issue> issueList = issueMapper.getIssuesByIds(issueIds);

        Map<Integer, List<ExamIssue>> examIssueMap = getExamIssueMap(examIssueList, issueList);

        for (Integer key : examIssueMap.keySet()) {
            int totalScore = 0;
            for (ExamIssue examIssue : examIssueMap.get(key)) {
                totalScore += examIssue.getScore();
            }
            result.put(IssueUtil.getIssueTypeName(key), totalScore);
        }

        return Response.ok(result);
    }

    @Override
    public Response getExamScoreDistribution(Integer courseId, Integer paperId) {
        Map<String, Integer> result = new HashMap<>();

        ExamPaper check = examPaperMapper.getPaperByCourseIdAndId(courseId, paperId);
        if (check == null) {
            return Response.ok(result);
        }

        List<ExamEvaluation> examEvaluationList = examEvaluationMapper.getEvaluationsByPaperId(paperId);
        if (examEvaluationList.size() == 0){
            return Response.ok(result);
        }

        for (ExamEvaluation examEvaluation : examEvaluationList) {
            if (examEvaluation.getScore() > check.getScore() * 0.85) {
                result.merge("excellent", 1, Integer::sum);
            } else if (examEvaluation.getScore() > check.getScore() * 0.75) {
                result.merge("good", 1, Integer::sum);
            } else if (examEvaluation.getScore() > check.getScore() * 0.65) {
                result.merge("pass", 1, Integer::sum);
            } else {
                result.merge("notPass", 1, Integer::sum);
            }
        }

        return Response.ok(result);
    }

    private Map<Integer, List<ExamIssue>> getExamIssueMap(List<ExamIssue> examIssueList, List<Issue> issueList) {
        Map<Integer, List<ExamIssue>> recordeMap = new HashMap<>();
        for (int i = 0; i < examIssueList.size(); i++) {
            if (issueList.get(i).getType().equals(IssueUtil.JUDGE)) {
                if (recordeMap.get(IssueUtil.JUDGE) == null) {
                    List<ExamIssue> issueRecords = new ArrayList<>();
                    issueRecords.add(examIssueList.get(i));
                    recordeMap.put(IssueUtil.JUDGE, issueRecords);
                } else {
                    List<ExamIssue> issueRecords = recordeMap.get(IssueUtil.JUDGE);
                    issueRecords.add(examIssueList.get(i));
                    recordeMap.put(IssueUtil.JUDGE, issueRecords);
                }
            } else if (issueList.get(i).getType().equals(IssueUtil.FILL_IN_THE_BLANKS)) {
                if (recordeMap.get(IssueUtil.FILL_IN_THE_BLANKS) == null) {
                    List<ExamIssue> issueRecords = new ArrayList<>();
                    issueRecords.add(examIssueList.get(i));
                    recordeMap.put(IssueUtil.FILL_IN_THE_BLANKS, issueRecords);
                } else {
                    List<ExamIssue> issueRecords = recordeMap.get(IssueUtil.FILL_IN_THE_BLANKS);
                    issueRecords.add(examIssueList.get(i));
                    recordeMap.put(IssueUtil.FILL_IN_THE_BLANKS, issueRecords);
                }
            } else if (issueList.get(i).getType().equals(IssueUtil.SINGLE_CHOICE)) {
                if (recordeMap.get(IssueUtil.SINGLE_CHOICE) == null) {
                    List<ExamIssue> issueRecords = new ArrayList<>();
                    issueRecords.add(examIssueList.get(i));
                    recordeMap.put(IssueUtil.SINGLE_CHOICE, issueRecords);
                } else {
                    List<ExamIssue> issueRecords = recordeMap.get(IssueUtil.SINGLE_CHOICE);
                    issueRecords.add(examIssueList.get(i));
                    recordeMap.put(IssueUtil.SINGLE_CHOICE, issueRecords);
                }
            } else if (issueList.get(i).getType().equals(IssueUtil.MULTIPLE_CHOICE)) {
                if (recordeMap.get(IssueUtil.MULTIPLE_CHOICE) == null) {
                    List<ExamIssue> issueRecords = new ArrayList<>();
                    issueRecords.add(examIssueList.get(i));
                    recordeMap.put(IssueUtil.MULTIPLE_CHOICE, issueRecords);
                } else {
                    List<ExamIssue> issueRecords = recordeMap.get(IssueUtil.MULTIPLE_CHOICE);
                    issueRecords.add(examIssueList.get(i));
                    recordeMap.put(IssueUtil.MULTIPLE_CHOICE, issueRecords);
                }
            } else {
                if (recordeMap.get(IssueUtil.BRIEF_ANSWER) == null) {
                    List<ExamIssue> issueRecords = new ArrayList<>();
                    issueRecords.add(examIssueList.get(i));
                    recordeMap.put(IssueUtil.BRIEF_ANSWER, issueRecords);
                } else {
                    List<ExamIssue> issueRecords = recordeMap.get(IssueUtil.BRIEF_ANSWER);
                    issueRecords.add(examIssueList.get(i));
                    recordeMap.put(IssueUtil.BRIEF_ANSWER, issueRecords);
                }
            }
        }
        return recordeMap;
    }

    @Override
    public Response getExamKnowledgeDistribution(Integer courseId, Integer paperId) {
        List<KnowledgeDistribution> result = new ArrayList<>();

        ExamPaper check = examPaperMapper.getPaperByCourseIdAndId(courseId, paperId);
        if (check == null) {
            return Response.ok(result);
        }

        List<ExamIssue> examIssueList = examIssueMapper.getExamIssueByPaperId(paperId);
        if (examIssueList.size() == 0){
            return Response.ok(result);
        }

        List<Integer> issueIds = new ArrayList<>();
        for (ExamIssue examIssue : examIssueList) {
            issueIds.add(examIssue.getIssueId());
        }

        List<Issue> issueList = issueMapper.getIssuesByIds(issueIds);
        Map<String, Integer> knowledgeMap = getKnowledgeMap(issueList);

        QueryWrapper<Chapter> chapterQueryWrapper = new QueryWrapper<>();
        chapterQueryWrapper.eq("course_id", courseId);
        List<Chapter> chapterList = chapterMapper.selectList(chapterQueryWrapper);

        for (String key : knowledgeMap.keySet()) {
            Knowledge knowledge = KnowledgeCache.knowledgeMap.get(Integer.parseInt(key));
            result.add(new KnowledgeDistribution(new KnowledgeMessage(knowledge, chapterList), knowledgeMap.get(key)));
        }

        return Response.ok(result);
    }

    private Map<String, Integer> getKnowledgeMap(List<Issue> issueList) {
        Map<String, Integer> map = new HashMap<>();
        for (Issue issue : issueList) {
            if (issue.getKnowledgeList() != null && !issue.getKnowledgeList().equals("")) {
                String[] ids = issue.getKnowledgeList().split("\\$");
                for (String id : ids) {
                    map.merge(id, 1, Integer::sum);
                }
            }
        }
        return map;
    }

    @Override
    public Response getIssueTypeDistribution(Integer courseId, Integer trainingExam) {
        List<Issue> issueList = issueMapper.getIssuesByCourseIdAndTrainingExam(courseId, trainingExam);
        if (issueList.size() == 0){
            return Response.error(ResultCode.NO_ISSUE_ERROR);
        }

        Map<Integer, List<Issue>> map = issueList.stream().collect(Collectors.groupingBy(
                Issue::getType));

        Map<String, Integer> result = new HashMap<>();
        for (Integer key : map.keySet()){
            result.put(IssueUtil.getIssueTypeName(key), map.get(key).size());
        }
        return Response.ok(result);
    }

    @Override
    public Response getIssueTypeAvgDifficulty(Integer courseId, Integer trainingExam) {
        Map<String, Float> result = new HashMap<>();

        List<Issue> issueList = issueMapper.getIssuesByCourseIdAndTrainingExam(courseId, trainingExam);
        if (issueList.size() == 0){
            return Response.ok(result);
        }

        Map<Integer, List<Issue>> map = issueList.stream().collect(Collectors.groupingBy(
                Issue::getType));

        for (Integer key : map.keySet()){
            float difficultyNum = 0;
            for (Issue issue : map.get(key)){
                difficultyNum += issue.getDifficulty();
            }
            float avgDiff = difficultyNum / map.get(key).size();

            result.put(IssueUtil.getIssueTypeName(key), (float)Math.round(avgDiff * 100) / 100);
        }

        return Response.ok(result);
    }

    @Override
    public Response getIssueDifficultyDistribution(Integer courseId, Integer trainingExam) {
        Map<Integer, Integer> result = new HashMap<>();

        List<Issue> issueList = issueMapper.getIssuesByCourseIdAndTrainingExam(courseId, trainingExam);
        if (issueList.size() == 0){
            return Response.ok(result);
        }

        Map<Integer, List<Issue>> map = issueList.stream().collect(Collectors.groupingBy(
                Issue::getDifficulty));

        for (Integer key : map.keySet()){
            result.put(key, map.get(key).size());
        }

        return Response.ok(result);
    }

    @Override
    public Response getChapterCorrectRate(Integer courseId, Integer studentId) {
        List<ChapterCorrectRate> result = new ArrayList<>();

        List<Chapter> chapterList = chapterMapper.selectAllByCourseId(courseId);
        if (chapterList.size() == 0){
            return Response.ok(result);
        }
        Map<String, List<IssueRecord>> listMap = new HashMap<>();
        for (Chapter chapter : chapterList){
            List<Integer> issueIdList = issueMapper.getIssueIdListByCourseIdAndChapterId(courseId, chapter.getId());
            if (issueIdList.size() == 0){
                listMap.put(chapter.getMessage(), new ArrayList<>());
                continue;
            }
            List<IssueRecord> issueRecordList = issueRecordMapper.getRecordsByStudentIdAndIssueIds(studentId, issueIdList);
            listMap.put(chapter.getMessage(), issueRecordList);
        }
        // 查询数据里被删除章节的题目
        List<Integer> issueIdList = issueMapper.getIssueIdListByCourseIdAndChapterId(courseId, 0);
        if (issueIdList.size() == 0){
            listMap.put("被删除章节", new ArrayList<>());
        }
        List<IssueRecord> issueRecordList = issueRecordMapper.getRecordsByStudentIdAndIssueIds(studentId, issueIdList);
        listMap.put("被删除章节", issueRecordList);


        for (String key : listMap.keySet()){
            if (listMap.get(key).size() == 0){
                result.add(new ChapterCorrectRate(key, 0f));
                continue;
            }
            float rightNum = 0;
            float wrongNum = 0;
            for (IssueRecord issueRecord : listMap.get(key)){
                rightNum += issueRecord.getRightNum();
                wrongNum += issueRecord.getWrongNum();
            }
            float correctRate = rightNum / (rightNum + wrongNum);
            result.add(new ChapterCorrectRate(key, (float)Math.round(correctRate * 100) / 100));
        }
        return Response.ok(result);
    }

    @Override
    public Response getStudentExamCondition(Integer courseId, Integer studentId) {
        List<ExamCondition> result = new ArrayList<>();

        List<Integer> classIdList = classStudentMapper.getClassIdByStudentId(studentId);
        if (classIdList.size() == 0){
            return Response.ok(result);
        }
        List<ExamPaper> examPaperList = new ArrayList<>();
        for (Integer classId : classIdList){

            QueryWrapper<ExamPaper> wrapper = new QueryWrapper<>();
            wrapper.eq("is_publish", 1)
                    .eq("is_finish", 1)
                    .eq("course_id", courseId)
                    .like( "classes", classId)
                    .orderByAsc("id");

            List<ExamPaper> paperList = examPaperMapper.selectList(wrapper);
            if (paperList.size() != 0){
                examPaperList.addAll(paperList);
            }
        }

        for (ExamPaper examPaper : examPaperList){
            ExamEvaluation examEvaluation = examEvaluationMapper.getEvaluationByPaperAndUserId(examPaper.getId(), studentId);
            result.add(new ExamCondition(examPaper, examEvaluation));
        }

        return Response.ok(result);
    }

    @Override
    public Response getStudentTrainingCorrectRate(Integer courseId, Integer studentId) {
        List<TrainingCorrectRate> result = new ArrayList<>();

        List<Issue> issueList = issueMapper.getIssueByCourseId(courseId);
        if (issueList.size() == 0){
            return Response.ok(result);
        }

        for (Issue issue : issueList){
            IssueRecord issueRecord = issueRecordMapper.getRecordByIssueIdAndStudentId(issue.getId(), studentId);
            if (issueRecord == null){
                continue;
            }

            float correctRate = (float) issueRecord.getRightNum() / (issueRecord.getRightNum() + issueRecord.getWrongNum());

            if (correctRate > 0.1) {
                result.add(new TrainingCorrectRate(issue, (float)Math.round(correctRate * 100) / 100));
            }
        }

        return Response.ok(result);
    }

    @Override
    public Response getWord(WordVo wordVo, HttpServletResponse response) {
        int courseId = wordVo.getCourseId(), classId = wordVo.getClassId(), paperId = wordVo.getPaperId();
        Course course = courseMapper.selectById(courseId);//课程
        User u = new User();
        u.setMyName("用户未找到");
        User teacher = UserCache.userMap.getOrDefault(course.getTeacher(),u);
        if(course == null) {
            return Response.error(ResultCode.PARAMETER_ERROR);
        }
        List<Integer> classIntegerList = classMapper.getClassIdsByCourse(courseId);//课程下班级Id列表
        if(!classIntegerList.contains(classId)) {
            return Response.error(ResultCode.PARAMETER_ERROR);
        }
        Class myClass = classMapper.selectById(classId);//班级
        List<Integer> studentInterList = classStudentMapper.getStudentIdByClassId(classId);//该班级下学生Id列表
        List<ExamEvaluation> examEvaluationList = examEvaluationMapper.getExamEvaluationsByStudentIds(paperId,studentInterList);//该班级下参加考试的学生、

        //获取试卷相关
        ExamPaper check = examPaperMapper.getPaperByCourseIdAndId(courseId, paperId);
        if (check == null) {
            return Response.error(ResultCode.GET_ERROR);
        }

        QueryWrapper<ExamIssue> examIssueQueryWrapper = new QueryWrapper<>();
        examIssueQueryWrapper
                .eq("paper_id", paperId)
                .orderByAsc("issue_id");
        List<ExamIssue> examIssueList = examIssueMapper.selectList(examIssueQueryWrapper);
        if (examIssueList.size() == 0){
            return Response.error(ResultCode.EXAM_NOT_HAVE_ISSUE_ERROR);
        }
        List<Integer> issueIds = new ArrayList<>();
        for (ExamIssue examIssue : examIssueList) {
            issueIds.add(examIssue.getIssueId());
        }

        QueryWrapper<Issue> issueQueryWrapper = new QueryWrapper<>();
        issueQueryWrapper
                .in("id", issueIds)
                .orderByAsc("id");
        List<Issue> issueList = issueMapper.selectList(issueQueryWrapper);

        int[] scores = {0,0,0,0,0,0};
        float average = 0;
        for (ExamEvaluation examEvaluation : examEvaluationList) {
            int score = examEvaluation.getScore();
            average = average + score;
            if (score >= 0 && score <= 29) {
                scores[0]++;
            } else if (score >= 30 && score <= 59) {
                scores[1]++;
            } else if (score >= 60 && score <= 69) {
                scores[2]++;
            } else if (score >= 70 && score <= 79) {
                scores[3]++;
            } else if (score >= 80 && score <= 89) {
                scores[4]++;
            } else {
                scores[5]++;
            }
        }
        average = average / examEvaluationList.size();

        NumberFormat numberInstance = NumberFormat.getNumberInstance();
        //        设置最大小数点位数
        numberInstance.setMaximumFractionDigits(2);
        //        设置数据舍入类型
        numberInstance.setRoundingMode(RoundingMode.HALF_UP);
        // 获取试卷难度分析
        String difficultyAnalysis = getPaperDifficultyAndAnalyse(check, issueList);
        // 获取成绩构成和试卷复核情况
        String compositionOfAchievements = getCompositionOfAchievements(check, examIssueList, issueList);
        try {
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("courseName", course.getName());
            dataMap.put("courseNature", wordVo.getCourseNature());
            dataMap.put("examMode", wordVo.getExamMode());
            dataMap.put("class", myClass.getClassName());
            dataMap.put("teacherName", teacher.getMyName());
            dataMap.put("classHour", course.getClassHour());
            dataMap.put("examPeopleNum", studentInterList.size());
            dataMap.put("nowExamPeopleNum", examEvaluationList.size());
            dataMap.put("average", average);
            dataMap.put("level1", scores[5]);
            dataMap.put("level2", scores[4]);
            dataMap.put("level3", scores[3]);
            dataMap.put("level4", scores[2]);
            dataMap.put("level5", scores[1]);
            dataMap.put("level6", scores[0]);
            dataMap.put("Blevel1", numberInstance.format((float)scores[5]/examEvaluationList.size()*100)+"%");
            dataMap.put("Blevel2", numberInstance.format((float)scores[4]/examEvaluationList.size()*100)+"%");
            dataMap.put("Blevel3", numberInstance.format((float)scores[3]/examEvaluationList.size()*100)+"%");
            dataMap.put("Blevel4", numberInstance.format((float)scores[2]/examEvaluationList.size()*100)+"%");
            dataMap.put("Blevel5", numberInstance.format((float)scores[1]/examEvaluationList.size()*100)+"%");
            dataMap.put("Blevel6", numberInstance.format((float)scores[0]/examEvaluationList.size()*100)+"%");
            dataMap.put("difficultyAnalysis", difficultyAnalysis);
            dataMap.put("compositionOfAchievements", compositionOfAchievements);
            dataMap.put("mainQuestion", "2021年9月9日");
            DocUtil.saveWord(dataMap,response);
            return Response.ok();
        }catch (Exception e){
            return Response.error(ResultCode.FILE_DOWNLOAD_ERROR);
        }
    }

    private String getPaperDifficultyAndAnalyse(ExamPaper examPaper, List<Issue> issueList){
        String paperDifficultyStr = getDifficultyStr(examPaper.getLevel());

        StringBuilder result = new StringBuilder("试卷包含");

        Map<Integer, List<Issue>> issueMap = issueList.stream().collect(Collectors.groupingBy(
                Issue::getType));

        Map<String, Float> issueResult = new HashMap<>();
        for (Integer key : issueMap.keySet()) {
            float difficulty = 0;
            for (Issue issue : issueMap.get(key)) {
                difficulty += issue.getDifficulty();
            }
            issueResult.put(getIssueTypeName(key), difficulty / issueMap.get(key).size());
        }

        result.append(StringUtils.join(issueResult.keySet(), '、'));
        result.append("几种题型");
        result.append(",每种题型的平均难度为:\n");
        for (String key : issueResult.keySet()){
            result.append(key);
            result.append(":");
            result.append(getDifficultyStr(issueResult.get(key)));
            result.append("(");
            result.append(String.format("%.2f", issueResult.get(key)));
            result.append(")");
            result.append("\n");
        }

        result.append("整张试卷的总体难度为：");
        result.append(paperDifficultyStr);
        result.append(";");

        Map<Integer, List<Issue>> chapterMap = issueList.stream().collect(Collectors.groupingBy(
                Issue::getChapterId));

        Map<String, Integer> chapterResult = new HashMap<>();
        for (Integer key: chapterMap.keySet()){
            if (key == 0 ){
                continue;
            }
            Chapter chapter = chapterMapper.getChapterById(key);
            if (chapterMap.get(key).size() > 1) {
                chapterResult.put(chapter.getMessage(), chapterMap.get(key).size());
            }
        }

        result.append("\n重点考察的章节：");
        result.append(StringUtils.join(chapterResult.keySet(), ','));
        result.append(";");

        Map<String, Integer> knowledgeMap = getKnowledgeMap(issueList);

        Map<String, Integer> knowledgeResult = new HashMap<>();
        for (String key : knowledgeMap.keySet()) {
            Knowledge knowledge = KnowledgeCache.knowledgeMap.get(Integer.parseInt(key));
            if (knowledgeMap.get(key) > 1) {
                knowledgeResult.put(knowledge.getMessage(), knowledgeMap.get(key));
            }
        }

        result.append("\n重点考察的知识点有：");
        result.append(StringUtils.join(knowledgeResult.keySet(), ','));
        result.append(";");

        return result.toString();
    }

    private String getCompositionOfAchievements(ExamPaper examPaper, List<ExamIssue> examIssueList, List<Issue> issueList){
        StringBuilder result = new StringBuilder("试卷包含");

        Map<Integer, List<ExamIssue>> examIssueMap = getExamIssueMap(examIssueList, issueList);

        Map<String, Integer> examIssueResult = new HashMap<>();
        for (Integer key : examIssueMap.keySet()) {
            int totalScore = 0;
            for (ExamIssue examIssue : examIssueMap.get(key)) {
                totalScore += examIssue.getScore();
            }
            examIssueResult.put(getIssueTypeName(key), totalScore);
        }

        result.append(StringUtils.join(examIssueResult.keySet(), '、'));
        result.append("几种题型");
        result.append("每种题型的总分值为：\n");
        for (String key : examIssueResult.keySet()){
            result.append(key);
            result.append(":");
            result.append(examIssueResult.get(key));
            result.append("，占试卷总分的");
            result.append(String.format("%.2f", (float)examIssueResult.get(key) / examPaper.getScore() * 100));
            result.append("%\n");
        }

        result.append("从本次试卷复查情况看，各教学单位对期末考试高度重视，管理严谨，均能按照学校要求组织安排考试，" +
                "进行试卷评阅、分析及成绩登录。试卷管理、存档等工作也不断规范化、科学化。在学校总体检查之前，大多数教学老师能做到提前自检" );

        List<PaperFeedback> paperFeedbackList = paperFeedbackMapper.getPaperFeedbackByPaperId(examPaper.getId(), examPaper.getCourseId());
        if (paperFeedbackList.size() == 0){
            result.append("。复查过程中，认真复核了试卷的主观题部分未发现漏评或登分、合分有误");
        }else {
            int handledNum = 0;
            int notHandledNum = 0;
            for (PaperFeedback paperFeedback : paperFeedbackList){
                if (paperFeedback.getIsHandle() == 1){
                    handledNum ++;
                }else {
                    notHandledNum ++;
                }
            }
            if (handledNum != 0) {
                result.append("。复查过程中，认真复核了");
                result.append(handledNum);
                result.append("人的试卷的主观题部分未发现漏评或登分、合分有误");
            }
            if (notHandledNum != 0){
                result.append("，目前还有");
                result.append(notHandledNum);
                result.append("人的复查申请未处理");
            }
        }

        result.append("。");

        return result.toString();
    }

    private String getDifficultyStr(float difficulty){
        if (Math.round(difficulty) == 1) {
            return "基础";
        } else if (Math.round(difficulty) == 2) {
            return "简单";
        } else if (Math.round(difficulty) == 3) {
            return "较简单";
        } else if (Math.round(difficulty) == 4) {
            return "较难";
        } else {
            return "困难";
        }
    }

    private String getIssueTypeName(int type){
        if (type == IssueUtil.JUDGE){
            return "判断";
        }else if (type == IssueUtil.FILL_IN_THE_BLANKS){
            return "填空";
        }else if (type == IssueUtil.SINGLE_CHOICE){
            return "单选";
        }else if (type == IssueUtil.MULTIPLE_CHOICE){
            return "多选";
        }else {
            return "简答";
        }
    }
}




